using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE;
using System.IO;

namespace IDEInterfaceLibrary
{
    /// <summary>
    /// Represents a VS ROOT building project
    /// 
    /// Invar: The project will be created while this object exists. This
    /// means ctor will create the project. :-)
    /// </summary>
    public class ROOTProject
    {
        /// <summary>
        /// The name of this project
        /// </summary>
        string _name;

        MSVCSolution _solution;

        Project _project;

        /// <summary>
        /// Create an empty project in the given directory.
        /// </summary>
        /// <param name="directory"></param>
        public ROOTProject(string directory, string projname, MSVCSolution sol)
        {
            _name = projname;
            _solution = sol;
            CreateProject(directory);
        }

        /// <summary>
        /// Actually creates a project in a directory.
        /// </summary>
        /// <param name="directory"></param>
        private void CreateProject(string directory)
        {
            _solution.IDESolution.AddFromTemplate(Configuration.Instance().ROOTProjectTemplate,
                directory + "\\" + Configuration.Instance().MSVCSubDirectory,
                _name + ".vcproj",
                false);

            FindProjectSafe();
        }

        /// <summary>
        /// Called to see if we can locate the project given by name _name in
        /// the solution. If we don't find it, return false. Set _project. No
        /// other side effect (like an exception).
        /// </summary>
        private bool FindProjectSafe()
        {
            ///
            /// If this project is already a member of the solution, then we
            /// will want to delete it!
            /// 

            foreach (Project p in _solution.IDESolution.Projects)
            {
                if (p.Name == _name)
                {
                    _project = p;
                    return true;
                }
            }

            ///
            /// Didn't find it. Outta here!
            ///

            return false;
        }


        /// <summary>
        /// Will find a project folder. If not there, create it..
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected ProjectItem FindProjectFolderCreate(string name)
        {
            ///
            /// Find the source folder and add the executable guy in there
            /// 

            foreach (ProjectItem pitem in _project.ProjectItems)
            {
                string pname = pitem.Name;
                if (pname == name)
                {
                    return pitem;
                }
            }

            return _project.ProjectItems.AddFolder(name, Constants.vsProjectItemKindVirtualFolder);
        }

        /// <summary>
        /// Add all files in this directory, and deeper, to the good old root thing.
        /// </summary>
        /// <param name="project_directory"></param>
        /// <param name="file_directory"></param>
        internal void AddFiles(string project_directory, string file_directory, UIHierarchy hr)
        {
            AddFiles(FindProjectFolderCreate(project_directory), file_directory, 0, hr);
        }

        /// <summary>
        /// Recursively add files from a particular directory.
        /// </summary>
        /// <param name="project_directory"></param>
        /// <param name="file_directory"></param>
        /// <param name="projectItem"></param>
        private void AddFiles(ProjectItem projectItem, string file_directory, int depth, UIHierarchy hr)
        {
            CloseAllItems(hr);
            DirectoryInfo dinfo = new DirectoryInfo(file_directory);
            foreach (FileInfo fname in dinfo.GetFiles())
            {
                projectItem.ProjectItems.AddFromFile(fname.FullName);
            }

            CloseAllItems(hr);
            int count = 0;
            DirectoryInfo[] dirs = dinfo.GetDirectories();
            foreach (DirectoryInfo dname in dirs)
            {
                count = count + 1;
                OnAddFileProgress(dname.FullName, depth, count, dirs.Length);
                ProjectItem itm = projectItem.ProjectItems.AddFolder(dname.Name, Constants.vsProjectItemKindVirtualFolder);
                AddFiles(itm, file_directory + "\\" + dname.Name, depth+1, hr);
            }
        }

        /// <summary>
        /// Callback for status
        /// </summary>
        /// <param name="dir_name">directory we are currently working on</param>
        /// <param name="depth">how many levels down we are</param>
        /// <param name="number">The # directory in the current level we are working on</param>
        /// <param name="total_number">how many directories there are in this level</param>
        public delegate void AddFileProgressCallback(string dir_name, int depth, int number, int total_number);

        public event AddFileProgressCallback AddFileProgress;

        void OnAddFileProgress(string dir_name, int depth, int number, int max_number)
        {
            if (AddFileProgress != null)
            {
                AddFileProgress(dir_name, depth, number, max_number);
            }
        }

        private void CloseAllItems(UIHierarchy hr)
        {
            CollapseAllItems(hr.UIHierarchyItems, 1);
        }

        /// <summary>
        /// Collapse all items down one level from here.
        /// </summary>
        /// <param name="toplevel"></param>
        static private void CollapseAllItems(UIHierarchyItems toplevel, int levels_down_to_leave)
        {
            ///
            /// If we have hit a closed node, then no need to go deepr
            /// 

            if (!toplevel.Expanded)
            {
                return;
            }

            ///
            /// Cycle through everything... and go down one
            /// 

            foreach (UIHierarchyItem item in toplevel)
            {
                CollapseAllItems(item.UIHierarchyItems, levels_down_to_leave-1);
                if (levels_down_to_leave <= 0)
                {
                    item.UIHierarchyItems.Expanded = false;
                }
            }
        }
    }
}
